package dw.systemutil;

import java.util.ArrayList;
import java.util.Currency;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;


/**
 * 
 */
public class I18nUtils
{
	public  static final int I18NKEY_MAXLENGTH = 100;
	
	private static final Map<Currency, List<Locale>> currencyToLocaleMap = new HashMap<Currency, List<Locale>>();

    static
    {
        Locale[] availableLocales = Locale.getAvailableLocales();
        for (Locale locale : availableLocales)
        {
            if (locale.getCountry() == null || locale.getCountry().length() != 2)
                continue;
            Currency currency = Currency.getInstance(locale);
            if (currency == null)
                continue;
            List<Locale> list;
            if (currencyToLocaleMap.containsKey(currency))
                list = currencyToLocaleMap.get(currency);
            else
            {
                list = new ArrayList<Locale>();
                currencyToLocaleMap.put(currency, list);
            }
            list.add(locale);
        }
    }

    /**
     * Gets the available Locales that use the specified Currency.
     * @return a List of Locale objects or null if no available locales use the specified currency
     * @see Locale#getAvailableLocales()
     */
    public static List<Locale> getAvailableLocales(Currency currency)
    {
        if (currencyToLocaleMap.containsKey(currency))
            return new ArrayList<Locale>(currencyToLocaleMap.get(currency));
        return null;
    }

    /**
     * Returns the parent Locale of the specified Locale or null if there
     * is not one.
     */
    public static Locale getParentLocale(Locale locale)
    {
        if (!StringUtils.isNullOrEmpty(locale.getVariant()))
            return new Locale(locale.getLanguage(), locale.getCountry());
        if (!StringUtils.isNullOrEmpty(locale.getCountry()))
            return new Locale(locale.getLanguage());
        return null;
    }

    /**
     * Translate the locale from something generic to something that is specific
     * to the country. Unfortunately the locale's listed below do not have
     * country codes for them and thus setting these locales on either currency
     * or some number formatters causes the application to NPE.  Thus we must 
     * translate them from something generic that we recieved from the browser
     * like ENGLISH to something more specific like US ENGLISH.
     * 
     * @param locale
     * @return A translated locale if it needs to be.
     */
    public static Locale translateLocale(Locale locale) {
        if ( Locale.ENGLISH.equals( locale ) )
            return Locale.US;
        if ( Locale.FRENCH.equals( locale ) )
            return Locale.FRANCE;
        if ( Locale.GERMAN.equals( locale ) )
            return Locale.GERMANY;
        if ( Locale.ITALIAN.equals( locale ) )
            return Locale.ITALY;
        if ( Locale.JAPANESE.equals( locale ) )
            return Locale.JAPAN;
        if ( Locale.KOREAN.equals( locale ) )
            return Locale.KOREA;
        if ( Locale.CHINESE.equals( locale ) )
            return Locale.SIMPLIFIED_CHINESE;

        return locale;
    }
    
    /**
     * Is the specified localeCountry an ISO country?
     * 
     * @param locale
     * @return true if localeCountry is non-null, 2 characters,
     * and a member of Locale.ISOCountries.
     */
    public static boolean isValidLocaleCountry( String localeCountry ) {
        boolean isValid = false;
        if ( localeCountry != null && localeCountry.length() == 2 ) {
            for ( String isoCountry : Locale.getISOCountries() ) {
                if ( isoCountry.equals( localeCountry ) ) {
                    isValid = true;
                    break;
                }
            }
        }
        return isValid;
    }
    
    /**
     * Is the specified localeLanguage an ISO language?
     * 
     * @param locale
     * @return true if localeLanguage is non-null, 2 characters,
     * and a member of Locale.ISOLanguages.
     */
    public static boolean isValidLocaleLanguage( String localeLanguage ) {
        boolean isValid = false;
        if ( localeLanguage != null && localeLanguage.length() == 2 ) {
            for ( String isoLanguage : Locale.getISOLanguages() ) {
                if ( isoLanguage.equals( localeLanguage ) ) {
                    isValid = true;
                    break;
                }
            }
        }
        return isValid;
    }
    
    public static Locale parseLocale( String value ) {
    	if ( StringUtils.isNullOrEmpty( value ) ) {
    		return null;
    	}
        // this is to ensure that I have a String[] with exactly 3 non-null values in it.
        // this saves logic trouble in creating the Locale object below.
        String[] split = value.split("_", 3);
        String[] localeValues = new String[] {"", "", ""};
        for (int i = 0; i < split.length; i++)
            localeValues[i] = split[i];
        
        Locale locale = new Locale(localeValues[0], localeValues[1], localeValues[2]);
        return locale;
    }
    
    /**
     * Generates a unique I18nKey that can be stored in the datbase.
     * The algorithm is to concatnate the passed in "context" strings
     * separated by a '.' and append a randomly generated uuid at the end.
     * This method also makes sure that the maxlength of the generated key
     * does not exceed the max length of the I18nKey type columns in the db
     * 
     */
    public static String generateUniqueI18nKey(String... context)
    {
    	StringBuilder sb = new StringBuilder(I18NKEY_MAXLENGTH);
    	final String randomUid = UUID.randomUUID().toString();
    	
    	if( context != null )
    	{
    		boolean first = true;
    		for(String s : context) 
    		{
    			if( !StringUtils.isNullOrEmpty(s))
    			{
    				if( first)
    					first = false;
    				else
    					sb.append('.');
    				sb.append(s);
    			}
    			if( sb.length() > I18NKEY_MAXLENGTH - randomUid.length())
    	    	{
    	    		sb.setLength(I18NKEY_MAXLENGTH - randomUid.length()-1);
    	    		break;
    	    	}
    		}
    	   	sb.append('.');
    	}
    	
    	sb.append(randomUid);
    	return sb.toString();
    }
    
}
